package com.guaoran.distributed.netty.chat.server;

import com.guaoran.distributed.netty.chat.protocol.IMDecoder;
import com.guaoran.distributed.netty.chat.protocol.IMEncoder;
import com.guaoran.distributed.netty.chat.server.handler.HttpHandler;
import com.guaoran.distributed.netty.chat.server.handler.SocketHandler;
import com.guaoran.distributed.netty.chat.server.handler.WebSocketHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.apache.log4j.Logger;

/**
 * @Author gucheng
 * @Description 聊天服务类
 * 2019-04-19 17:09
 */
public class ChatServer {
    private Logger logger = Logger.getLogger(this.getClass());
    private final int port = 80;

    public static void main(String[] args) {
        new ChatServer().start();
    }
    /**
     * 启动服务类
     */
    public void start(){
        // 创建两个 NIO 的 线程池
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // 创建一个server bootstrap
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap
                .group(bossGroup,workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG,1024)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();

                        // 解析自定义协议
                        pipeline.addLast(new IMDecoder());
                        pipeline.addLast(new IMEncoder());
                        pipeline.addLast(new SocketHandler());

                        // 解析Http 请求
                        pipeline.addLast(new HttpServerCodec());
                        // 主要是将同一个http请求或响应的多个消息对象变成一个完整的消息对象
                        // TODO FullHttpRequest 或 FullHttpResponse
                        pipeline.addLast(new HttpObjectAggregator(1024*64));
                        // 主要用于处理大数据流，
                        // 比如一个1G大小的文件如果直接出书肯定会撑爆JVM 内存，
                        // 加上这个handler 就不用考虑这个问题了
                        pipeline.addLast(new ChunkedWriteHandler());
                        pipeline.addLast(new HttpHandler());

                        // 解析 WebSocket 请求
                        // 用于绑定 webSocket 协议的类型是 im 协议
                        pipeline.addLast(new WebSocketServerProtocolHandler("/im"));
                        pipeline.addLast(new WebSocketHandler());

                    }
                });
            ChannelFuture future = bootstrap.bind(this.port).sync();
            logger.info("服务已启动，监听端口："+this.port);
            future.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.error(e.getMessage(),e);
        }finally {
            // TODO ？？？
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
